import Clock.ClockFactory;
import Clock.ClockI;
import ElevatorP.ElevatorI;

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.*;

/**
 * Created by Connor Madden.
 * User: Connor Madden
 * Date: 8/09/11
 * Time: 5:02 PM
 */
public class GUI {
    public static int
            FLOOR_COLUMN = 2,
            ELEVATOR_COLUMN = 1,
            BUTTON_COLUMN = 0;
    public static String
            ELEV_OPEN_IMG_PATH = "images\\elev_open.gif",
            ELEV_CLOSED_IMG_PATH = "images\\elev_closed.gif";

    private JPanel cardPanel, startupPanel, mainPanel, settingsPanel, buildingPanel, elevPanel;
    private JButton createNewSimulationButton, loadSimulationFromDatabaseButton,
            runSimulationButton, cancelButton, pauseButton, muteButton;
    private JLabel runningState;
    private JFormattedTextField numFloorsFormattedTextField, numElevatorsFormattedTextField,
            floorHeightFormattedTextField, topSpeedFormattedTextField;
    private JButton autoOnButton;
    private boolean simulationLoaded;
    private Simulation currentSim;
    private BufferedImage elevOpenImg, elevClosedImg;
    private Dimension elevImgMaxDim;
    private TreeMap<Integer, JLabel> elevImgs;
    private TreeMap<Integer, JComponent> floorLocMap;

    public GUI() {
        loadImgs();
        simulationLoaded = false;
        createNewSimulationButton.addActionListener(new ActionListener() {
            /**
             * Invoked when an action occurs.
             */
            public void actionPerformed(ActionEvent e) {
                CardLayout cl = (CardLayout) cardPanel.getLayout();
                cl.show(cardPanel, "settingsCard");
            }
        });
        cancelButton.addActionListener(new ActionListener() {
            /**
             * Invoked when an action occurs.
             */
            public void actionPerformed(ActionEvent e) {
                CardLayout cl = (CardLayout) cardPanel.getLayout();
                if (simulationLoaded) {
                    cl.show(cardPanel, "mainCard");
                } else {
                    cl.show(cardPanel, "startupCard");
                }
            }
        });
        runSimulationButton.addActionListener(new ActionListener() {
            /**
             * Invoked when an action occurs.
             */
            public void actionPerformed(ActionEvent e) {
                currentSim = new Simulation(2, 8, 2);      // DEBUG
//                currentSim = new Simulation(
//                        (Integer) numElevatorsFormattedTextField.getValue(),
//                        (Double) floorHeightFormattedTextField.getValue(),
//                        (Integer) numFloorsFormattedTextField.getValue(),
//                        (Double) topSpeedFormattedTextField.getValue());
                initMainView();
                CardLayout cl = (CardLayout) cardPanel.getLayout();
                cl.show(cardPanel, "mainCard");
            }
        });
        pauseButton.addActionListener(new ActionListener() {
            /**
             * Invoked when an action occurs.
             */
            public void actionPerformed(ActionEvent e) {
                JButton pauseButton = (JButton) e.getSource();
                if (pauseButton.getName().equals("Pause")) {
                    currentSim.stop();
                    pauseButton.setText("Play");
                    pauseButton.setName("Play");
                } else {
                    currentSim.run();
                    pauseButton.setText("Pause");
                    pauseButton.setName("Pause");
                }
            }
        });
    }

    private Dimension imageExpandDimensions(BufferedImage image, Dimension d) {
        int dimHeight = (int) d.getHeight();
        int dimWidth = (int) d.getWidth();
        int imgHeight = image.getHeight();
        int imgWidth = image.getWidth();
        if (dimHeight < imgHeight) {
            dimHeight = imgHeight;
        }
        if (dimWidth < imgWidth) {
            dimWidth = imgWidth;
        }
        return new Dimension(dimWidth, dimHeight);
    }

    private void loadImgs() {
        String file = null;
        Dimension maxImageDim = new Dimension(0, 0);
        try {
            file = ELEV_CLOSED_IMG_PATH;
            elevClosedImg = ImageIO.read(new File(file));
            maxImageDim = imageExpandDimensions(elevClosedImg, maxImageDim);

            file = ELEV_OPEN_IMG_PATH;
            elevOpenImg = ImageIO.read(new File(file));
            maxImageDim = imageExpandDimensions(elevOpenImg, maxImageDim);

        } catch (IOException e) {
            JOptionPane.showMessageDialog(null,
                    e.getLocalizedMessage() + " \"" + file + "\"",
                    "Critical Error Encountered",
                    JOptionPane.ERROR_MESSAGE);
            e.printStackTrace();
            System.exit(1);
        }
        elevImgMaxDim = maxImageDim;
    }

    private void initMainView() {
        initBuildingPanel();
    }

    private void initBuildingPanel() {
        GridBagConstraints flrLblCons = new GridBagConstraints();
        GridBagConstraints callBttnCons = new GridBagConstraints();
        flrLblCons.anchor = GridBagConstraints.CENTER;
        callBttnCons.anchor = GridBagConstraints.CENTER;
        int numFloors = currentSim.getNumFloors();
        int componentPadding;
        floorLocMap = new TreeMap<Integer, JComponent>();
        for (int floor = 0; floor < numFloors - 1; floor++) {
            JLabel flrLbl;
            JButton callBttn;
            String name;

            name = "Floor " + floor;
            flrLblCons.gridy = numFloors - floor;
            callBttnCons.gridy = numFloors - floor;
            flrLblCons.gridx = FLOOR_COLUMN;
            flrLbl = new JLabel(name);
            componentPadding = (int) ((elevImgMaxDim.getHeight() - flrLbl.getMinimumSize().getHeight()) / 2);
            flrLblCons.insets = new Insets(componentPadding, 0, componentPadding, 0);
            buildingPanel.add(flrLbl, flrLblCons);

            callBttnCons.gridx = BUTTON_COLUMN;
            callBttn = new JButton("call");
            callBttn.setName(String.valueOf(floor));
            componentPadding = (int) ((elevImgMaxDim.getHeight() - callBttn.getMinimumSize().getHeight()) / 2);
            callBttnCons.insets = new Insets(componentPadding, 0, componentPadding, 0);
            buildingPanel.add(callBttn, callBttnCons);
            floorLocMap.put(floor, flrLbl);
            callBttn.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    JButton callBttn = (JButton) e.getSource();
                    final JLabel elev = elevImgs.firstEntry().getValue();
                    final ElevatorI elevator = currentSim.getElevators().getFirst();
                    currentSim.newArrival(Integer.parseInt(callBttn.getName()), 0);
                    ClockI clock = ClockFactory.getClock(10, this);
                    clock.addObserver(new Observer() {
                        public void update(Observable o, Object arg) {
                            for (ElevatorI elevatorI : currentSim.getElevators()) {
                                repaintElevImg(elevImgs.get(elevatorI.getNum()), elevatorI.getLocation());
                            }
                        }
                    });
                    clock.start();
                }
            });
        }
        initElevPanel();
    }

    private void initElevPanel() {
        GridBagConstraints elevatorConstraints = new GridBagConstraints();
        elevatorConstraints.gridy = 0;
        elevatorConstraints.gridx = ELEVATOR_COLUMN;
        elevatorConstraints.gridheight = currentSim.getNumFloors() + 1;
        elevatorConstraints.fill = GridBagConstraints.VERTICAL;
        elevPanel = new JPanel(new FlowLayout());

        elevImgs = new TreeMap<Integer, JLabel>();
        LinkedList<ElevatorI> simElev = currentSim.getElevators();
        for (ElevatorI aSimElev : simElev) {
            JLabel elevImg = new JLabel(new ImageIcon(elevClosedImg));
            elevPanel.add(elevImg);
            elevImgs.put(aSimElev.getNum(), elevImg);
        }

        buildingPanel.add(elevPanel, elevatorConstraints);
        for (ElevatorI aSimElev : simElev) {
            repaintElevImg(elevImgs.get(aSimElev.getNum()), aSimElev.getLocation());
        }
    }

    private void repaintElevImg(JComponent elevImg, float floor) {
        int top = (int) ((currentSim.getNumFloors() - floor - 2.0f) * elevImgMaxDim.height) - 5;
        int bottom = (int) (floor * elevImgMaxDim.height) - 5;
        elevImg.setBorder(new CompoundBorder(BorderFactory.createLineBorder(Color.red), new EmptyBorder(top, 0, bottom, 0)));
    }

    public static void start() {
        JFrame frame = new JFrame("GUI");
        frame.setContentPane(new GUI().cardPanel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
        frame.setResizable(true);
    }

    private void createUIComponents() {
        pauseButton = new JButton();
        muteButton = new JButton();
        pauseButton.setName("Pause");
    }
}
